from typing import Any

from aiogram import Bot, F, types
from aiogram_dialog import DialogManager, Window
from aiogram_dialog.widgets.input import TextInput
from aiogram_dialog.widgets.kbd import Back, Button, Cancel
from pydantic import ValidationError
from sqlalchemy.exc import DBAPIError

from app.bot.dialog.dialog_states import SelectProxySG
from app.bot.dialog.getters.orders import order_summary_getter
from app.bot.dialog.getters.proxies import available_proxy_amount_getter
from app.bot.dialog.widgets import LocaleText
from app.bot.handlers.client.orders.orders_history import user_orders
from app.bot.schemas.order import OrderModel
from app.bot.services.broadcaster import broadcast
from app.bot.services.date_time import get_date_time
from app.bot.services.helpers import get_expiring_on
from app.bot.services.locale import Locale
from app.bot.services.loggers import logger
from app.config import Settings
from app.database.services.categories import get_category, get_category_for_private
from app.database.services.orders.common import create_order
from app.database.services.proxy import get_available_proxies
from app.database.services.stats import update_stats
from app.database.services.users import get_user


async def set_order_quantity(
    message: types.Message, widget: Any, manager: DialogManager, selected_amount: str
):
    locale: Locale = manager.middleware_data.get("locale")

    selected_amount = int(selected_amount)

    if selected_amount <= 0:
        await message.answer(locale.get("number-must-be-positive"))
        return

    manager.dialog_data["selected_amount"] = selected_amount
    manager.dialog_data["user_id"] = message.from_user.id

    locale: Locale = manager.middleware_data.get("locale")

    if selected_amount > manager.dialog_data.get("available_amount"):
        await message.answer(locale.get("too-much-quantity"))
        return

    await manager.switch_to(SelectProxySG.create_order)


async def back_to_provider(
    call: types.CallbackQuery, widget: Any, manager: DialogManager
):
    await manager.switch_to(SelectProxySG.list_of_providers)


async def add_order(message: types.Message, widget: Any, manager: DialogManager):
    db_session = manager.middleware_data.get("db_session")
    locale: Locale = manager.middleware_data.get("locale")
    bot: Bot = manager.middleware_data.get("bot")
    config: Settings = manager.middleware_data.get("config")

    order_summ: float = manager.dialog_data.get("order_summ")

    user_id: int = message.from_user.id
    user = await get_user(db_session, user_id)

    if user.balance < order_summ:
        await message.answer(locale.get("not-enough-balance", balance=user.balance))
        return

    try:
        selected_amount: int = manager.dialog_data.get("selected_amount")
        category_id: int = manager.dialog_data.get("category_id")
        period: str = manager.dialog_data.get("period")
        proxy_type: str = manager.dialog_data.get("proxy_type")
        proxy_privacy: str = manager.dialog_data.get("proxy_privacy")
        country_id: int = manager.dialog_data.get("country_id")
        provider_id: int = manager.dialog_data.get("provider_id")
        site_id: int = manager.dialog_data.get("site_id")
        user_telegram_id: int = manager.middleware_data.get("event_from_user").id

        date_now = get_date_time(get_datetime=True)

        expiring_on = await get_expiring_on(date_now, period)

        if category_id:
            category = await get_category(db_session, category_id)
        else:
            category = await get_category_for_private(
                db_session, country_id, provider_id
            )

        proxies = await get_available_proxies(
            session=db_session,
            proxy_type=proxy_type,
            proxy_privacy=proxy_privacy,
            country_id=country_id,
            provider_id=provider_id,
            category=category,
            site_id=site_id,
            limit=selected_amount,
            user_telegram_id=user_telegram_id,
        )

        if selected_amount > len(proxies):
            await message.answer(locale.get("too-much-quantity"))
            return

        order = OrderModel(
            type="proxy",
            user_id=user_id,
            proxies=proxies,
            country_id=country_id,
            summ=order_summ,
            period=period,
            provider_id=provider_id,
            category_id=category.id,
            site_id=site_id,
            expiring_on=expiring_on,
        )

        order = await create_order(db_session, **order.dict())

        if manager.start_data and manager.start_data.get("for_test"):
            user.test_proxy_acquired = date_now

        if proxy_type == "mobile":
            await update_stats(db_session, mobile_proxies_bought=len(proxies))
        elif proxy_type == "server":
            await update_stats(db_session, server_proxies_bought=len(proxies))

        await message.answer(locale.get("order-success"))
        await db_session.commit()
        logger.info(f"Добавлен новый заказ {order.id}")
        await manager.switch_to(SelectProxySG.order_created)

    except (DBAPIError, ValidationError, Exception) as e:
        logger.exception(e)
        await message.answer(locale.get("error-msg"))
        await broadcast(
            bot,
            [config.tg_bot.developer_id],
            f"Ошибка во время создания заказа {str(e)}",
        )


set_order_quantity_window = Window(
    LocaleText(
        "select-amount",
        available_amount="{available_amount}",
        when=F["available_amount"] > 0,
    ),
    LocaleText("no-test-proxies", when=F["available_amount"] <= 0),
    TextInput("orderquantityinp", int, on_success=set_order_quantity),
    Back(LocaleText("back-btn"), when=~F["for_test"]),
    Button(
        LocaleText("back-btn"),
        id="back_btn",
        on_click=back_to_provider,
        when=F["for_test"],
    ),
    Cancel(LocaleText("cancel-btn")),
    state=SelectProxySG.set_order_quantity,
    getter=available_proxy_amount_getter,
)


create_order_windows = Window(
    LocaleText("order-overview"),
    LocaleText("proxy-type", proxy_type="{proxy_type}"),
    LocaleText("proxy-privacy", proxy_privacy="{proxy_privacy}"),
    LocaleText("proxy-country", country="{country}"),
    LocaleText("proxy-provider", provider="{provider}"),
    LocaleText("proxy-category", category="{category}"),
    LocaleText("proxy-site", site="{site}", when=F["site"]),
    LocaleText("selected-period", period="{period}"),
    LocaleText("selected-amount", amount="{selected_amount}"),
    LocaleText("order-summ", order_summ="{order_summ}$"),
    Button(
        LocaleText("confirm-btn"),
        id="confirm_order_button",
        on_click=add_order,
    ),
    Back(LocaleText("back-btn")),
    Cancel(LocaleText("cancel-btn")),
    state=SelectProxySG.create_order,
    getter=order_summary_getter,
)


item_order_created_window = Window(
    LocaleText("order-created"),
    Button(LocaleText("orders-btn"), id="proxy", on_click=user_orders),
    Cancel(LocaleText("main-menu-btn")),
    state=SelectProxySG.order_created,
)
